#!/usr/bin/env python

__author__ = "Abhinav Sarkar"
__version__ = "0.1"
__license__ = "GNU Lesser General Public License"

class Track (object):
	"""A class representing a track.
	
	The Track class exposes the following instance properties:
	
		track.album
		track.artist
		track.name
		track.streamable
		track.url
		track.similarTracks
		track.topFans
		track.topFan
		track.topTags
		track.topTag
		
	The Track class exposes the following instance methods:
	
		track.GetSimilarTracks
		track.GetTopFans
		track.GetTopTags
	"""
	def __init__(self,
				 artist = None,
				 album = None,
				 name = None,
				 url = None,
				 streamable = None):
		"""
		An object to hold a track.
		
		This class is normally instantiated by the Webservice class.
		
		Args:
			artist: an Artist object corresponding to this track's artist
			album: an Album object corresponding to this track's album
			name: name of this track
			url: URL of this track on last.fm
			streamable:
				a boolean value indicating whether this track is
				streamable from last.fm

		Usage:
			>>> import audioscrobblerws
			>>> ws = audioscrobblerws.Webservice()
			>>> track = ws.GetTrack('Last man standing', 'bon jovi')
		"""
		self.artist = artist
		self.album = album
		self.name = name
		self.url = url
		self.streamable = streamable

	def GetSimilarTracks(self):
		"""Get the tracks similar to this track.
		
		Returns:
			An ordered list of Track objects corresponding to the tracks
			similar to this track.
			
		Usage:
			>>> track = ws.GetTrack('Last man standing', 'bon jovi')
			>>> similarTracks = track.GetSimilarTracks()
			>>> [(t.name, t.artist.name) for t in similarTracks[:5]]
			[('Hard Times Come Easy', 'Richie Sambora'), ('Undiscovered Soul', 'Richie Sambora'), 
			('Destination Anywhere', 'Jon Bon Jovi'), ("It's Just Me", 'Jon Bon Jovi'), 
			('Up the River', 'David Bryan')]
		"""
		if not (self.name and self.artist):
			raise AudioscrobblerError("track name has to be set before calling this method")
		url = "http://ws.audioscrobbler.com/1.0/track/%s/%s/similar.xml" %\
				(self.artist.name, self.name)
		xml = Webservice()._FetchUrl(url)
		data = Xml2Dict(ElementTree.XML(xml))

		tracks = []
		if not 'track' in data:
			return tracks

		for trackData in data['track']:
			track = Track(
				artist = Artist(
							name = trackData['artist']['name'],
							url = trackData['artist']['url']
						),
				name = trackData['name'],
				url = trackData['url'],
				streamable = trackData['streamable'] == '1'
			)

			track.match = float(trackData['match'])
			tracks.append(track)
		return tracks

	similarTracks = property(GetSimilarTracks,
		doc = "Tracks similar to this track")
	
	def GetTopFans(self):
		"""Get the top fans of this track.
		
		Returns:
			An ordered list of User objects corresponding to the top fans of this track.
			
		Usage:
			>>> track = ws.GetTrack('Last man standing', 'bon jovi')
			>>> topFans = track.GetTopFans()
			>>> [f.username for f in topFans[:10]]
			['dragotina', 'Nicky5', 'Mautiz', 'rockerman82', 'jovirakel', 'fagauss', 'rombio', 
			'shafnyz', 'chachakobaka', 'safija']
		"""
		if not (self.name and self.artist):
			raise AudioscrobblerError("track name and artist has to be set before calling this method")
		url = "http://ws.audioscrobbler.com/1.0/track/%s/%s/fans.xml" %\
				(self.artist.name, self.name)
		xml = Webservice()._FetchUrl(url)
		data = Xml2Dict(ElementTree.XML(xml))

		users = []
		if not 'user' in data:
			return users

		for userData in data['user']:
			user = User(username = userData['@username'],
						avatar = userData['image'],
						url = userData['url'])
			user.weight = int(userData['weight'])
			users.append(user)
		return users

	topFans = property(GetTopFans,
		doc = "Top fans of this track")
	topFan = property(lambda (self): len(self.GetTopFans()) and self.GetTopFans()[0] or None,
		doc = "Topmost fan of this track")

	def GetTopTags(self):
		"""Get top tags for this track.
		
		Returns:
			An ordered list of Tag objects corresponding to the top tags for this track.
			
		Usage:
			>>> track = ws.GetTrack('Last man standing', 'bon jovi')
			>>> topTags = track.GetTopTags()
			>>> [t.name for t in topTags[:10]]
			['rock', 'classic rock', 'bon jovi', 'hard rock', 'favorites', 'bonjovi', 
			'on repeat', 'melodic rock', 'music chrtienne', 'igor']		
		"""
		if not (self.name and self.artist):
			raise AudioscrobblerError("track name and artist has to be set before calling this method")
		url = "http://ws.audioscrobbler.com/1.0/track/%s/%s/toptags.xml" %\
				(self.artist.name, self.name)
		xml = Webservice()._FetchUrl(url)
		data = Xml2Dict(ElementTree.XML(xml))

		tags = []
		if not 'tag' in data:
			return tags

		for tagData in data['tag']:
			tag = Tag(
				name = tagData['name'],
				url = tagData['url'],
			)

			tag.count = int(tagData['count'])
			tags.append(tag)
		return tags

	topTags = property(GetTopTags,
		doc = "Top tags for this track")
	topTag = property(lambda (self): len(self.GetTopTags()) and self.GetTopTags()[0] or None,
		doc = "Topmost tag for this track")
	
	def AsDict(self):
		"""Returns self as a dict."""
		return self.__dict__

	def __eq__(self, other):
		return self.name == other.name and self.artist == other.artist

	def __ne__(self, other):
		return not self.__eq__(other)

import cElementTree as ElementTree

from album import Album
from artist import Artist
from webservice import Webservice
from tag import Tag
from user import User
from xml2dict import Xml2Dict
from error import AudioscrobblerError